﻿using System.Collections.Generic;
using System.Linq;
using Reactor.Environment;
using Reactor.Messages.Replies.Diagnostics;
using Reactor.Messages.Requests.Diagnostics;
using Reactor.Messaging.Attributes;
using Map = Reactor.Messages.Replies.Diagnostics.EndpointDiagnosticsResponse.DestinationToMessageTypesMap;

namespace Reactor.Messaging.MessageHandlers
{
    [PointToPointChannel]
    public class EndpointDiagnosticsRequestHandler : IMessageHandler<EndpointDiagnosticsRequest>
    {
        #region Implementation of IMessageHandler<EndpointDiagnosticsRequest>

        /// <summary>
        /// Handles the message.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <param name="messageContext">Context provided with message deliver</param>
        public void Handle(EndpointDiagnosticsRequest message, IMessageContext messageContext)
        {
            var handlerRegistry = Context.ServiceBus.Configuration.MessageHandlerRegistry;
            var destinationRegistry = Context.ServiceBus.Configuration.DestinationRegistry;
            var handlerRegistrations = handlerRegistry.GetAllHandlerRegistrations();

            var maps = new List<Map>();
            foreach (var handlerRegistration in handlerRegistrations)
            {
                foreach (var expectedDestination in handlerRegistration.ExpectedDestinations)
                {
                    var ed = expectedDestination;
                    var typedName = ed.GetTypedDestinationName();
                    var existing = maps.FirstOrDefault(m => m.DestinationName == typedName);
                    if(existing != null)
                    {
                        // Update existing map with message type names
                        if (!existing.MessageTypeNames.Contains(handlerRegistration.MessageType.FullName))
                            existing.MessageTypeNames =
                                new List<string>(existing.MessageTypeNames) { handlerRegistration.MessageType.FullName }.ToArray();
                    }
                    else
                    {
                        var newMap = new Map
                                         {
                                             DestinationName = typedName,
                                             MessageTypeNames = new[] {handlerRegistration.MessageType.FullName}
                                         };
                        maps.Add(newMap);
                    }
                }
            }

            var response = new EndpointDiagnosticsResponse
                               {
                                   DestinationToMessageTypesMaps = maps.ToArray(),
                                   SubscriberName = destinationRegistry.InstanceSubscriber.Name
                               };

            messageContext.Reply(response);
        }

        #endregion
    }
}
